// ===============================================================================
// scan: sequential scan of a large descriptor collection
// Created in September 2007 as a project for an Advanced Database Systems course
// (c) Reykjavik University, Björn Þór Jónsson, Kristleifur Daðason, Herwig Lejsek
// Contact author: Björn Þór Jónsson, Reykjavík University, bjorn@ru.is
// ===============================================================================

#include <iostream>
#include <fstream>
#include <vector>
#include <cmath>

#include "FlexDescriptor.h"
#include "DescMapper.h"
#include "QueryDescInfo.h"

#include "ConfigMapper.h"
#include "IndexMapper.h"
#include "ClusterMapper.h"

#include "SequentialScan.h"
#include "Aggregate.h"

using namespace std;

int main(int argc, char *argv[])
{
	if (argc < 4 ) {
		cout << "Usage:\t'scan <query list> <config file> <neighbors>' or \n" 
			<< "\t'scan <query list> <config file> <neighbors> <clustercount>'"<< endl;
		exit(0);
	}

	// Prepare the database for queries
	ConfigMapper *cnfg = new ConfigMapper(argv[2]);
	IndexMapper  *indx = new IndexMapper(cnfg);
		
	// Number of neighbors to retrieve
	int nns = atoi(argv[3]);
	int clusterstosearch = 0;
	if (argc == 5) {
		clusterstosearch = atoi(argv[4]);
		if (clusterstosearch < 1) {
			cout << "Clustercount must be greater then 0"<<endl;
			exit(0);
		}
		else if (clusterstosearch > indx->getNumClusters()) {
			cout << "clustercount is greater then the number of clusters in data file.("<<indx->getNumClusters()<<")."<<endl;
			exit(0);
		}
		cout << "Performing clusterd search with clustercount set to "<<clusterstosearch<<endl;
	}
	else {
		cout << "Performing sequential serach"<<endl;
	}
	
	// For each file in the query list, run the sequential scan
	// note that while reading all files and running a single scan would
	// be a little bit more efficient, it is less likely to happen in a 
	// real life scenario!
	string queryfile;
	ifstream querylist(argv[1]);
	while(getline(querylist, queryfile)) {

		// We have a query, so map the descriptors into memory
		DescMapper *qdescs = new DescMapper(queryfile, cnfg->getNumDims());
		
		cout << queryfile << endl;
		QueryDescInfo **qinfos;
		if (clusterstosearch > 0) {
			// Do the cluster scan
			qinfos = CScan(qdescs, cnfg, indx, nns, clusterstosearch);
		}
		else {
			// Do the sequential scan			
			qinfos = Scan(qdescs, cnfg, indx, nns);
		}		
		
		cout << "gone past Scan" << endl;
		//Aggregate and print the results
		AggregateResults(qinfos, qdescs->getNumDescs(), queryfile, cnfg);

		// Clean up the data structures
		for (int i=0; i<qdescs->getNumDescs(); i++)
			delete qinfos[i];
		delete qinfos;
		delete qdescs;
	}

	// Clean up the global structures
	delete indx;
	delete cnfg;
};
